

/**
 * 
 *
 * Copyright (c) 2012-2013 JLLT Corp. 2012-2013,All Rights Reserved.
 * This software is published under the 金麟龙腾商贸有限公司.
 * License version 1.0, a copy of which has been included with this
 * distribution in the LICENSE.txt file. 
 *
 * @File name:  JsonUtils.java   包含操作 {@code JSON} 数据的常用方法的工具类。 
 * @Create on:  2012-07-18 22:23:111
 * @Author      :  高宇舟
 *
 * @ChangeList
 * ---------------------------------------------------
 * Date         Editor              ChangeReasons
 *
 */

package com.boho.ecp.util;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

/** 
 * 工具类的使用案例： 
 * 
 * <pre> 
 * public class User {  
 *     @SerializedName("pwd") 
 *     private String password;  
 *     @Expose 
 *     @SerializedName("uname") 
 *     private String username;  
 *     @Expose 
 *     @Since(1.1) 
 *     private String gender;  
 *     @Expose 
 *     @Since(1.0) 
 *     private String sex;  
 *       
 *     public User() {}  
 *     public User(String username, String password, String gender) {  
 *         // user constructor code... ... ...  
 *     }  
 *       
 *     public String getUsername()  
 *     ... ... ...  
 * } 
 * List<User> userList = new LinkedList<User>();  
 * User jack = new User("Jack", "123456", "Male");  
 * User marry = new User("Marry", "888888", "Female");  
 * userList.add(jack);  
 * userList.add(marry);  
 * Type targetType = new TypeToken<List<User>>(){}.getType();  
 * String sUserList1 = JSONUtils.toJson(userList, targetType);  
 * sUserList1 ----> [{"uname":"jack","gender":"Male","sex":"Male"},{"uname":"marry","gender":"Female","sex":"Female"}]  
 * String sUserList2 = JSONUtils.toJson(userList, targetType, false);  
 * sUserList2 ----> [{"uname":"jack","pwd":"123456","gender":"Male","sex":"Male"},{"uname":"marry","pwd":"888888","gender":"Female","sex":"Female"}]  
 * String sUserList3 = JSONUtils.toJson(userList, targetType, 1.0d, true);  
 * sUserList3 ----> [{"uname":"jack","sex":"Male"},{"uname":"marry","sex":"Female"}] 
 * </pre> 
 */
public class JsonUtils {
	private static final Logger LOGGER = LoggerFactory
			.getLogger(JsonUtils.class);
	/** 空的 {@code JSON} 数据 - <code>"{}"</code>。 */
	public static final String EMPTY_JSON = "{}";
	/** 空的 {@code JSON} 数组(集合)数据 - {@code "[]"}。 */
	public static final String EMPTY_JSON_ARRAY = "[]";
	/** 默认的 {@code JSON} 日期/时间字段的格式化模式。 */
	public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss SSS";
	/** {@code Google Gson} 的 <code>@Since</code> 注解常用的版本号常量 - {@code 1.0}。 */
	public static final double SINCE_VERSION_10 = 1.0d;
	/** {@code Google Gson} 的 <code>@Since</code> 注解常用的版本号常量 - {@code 1.1}。 */
	public static final double SINCE_VERSION_11 = 1.1d;
	/** {@code Google Gson} 的 <code>@Since</code> 注解常用的版本号常量 - {@code 1.2}。 */
	public static final double SINCE_VERSION_12 = 1.2d;
	/** {@code Google Gson} 的 <code>@Until</code> 注解常用的版本号常量 - {@code 1.0}。 */
	public static final double UNTIL_VERSION_10 = SINCE_VERSION_10;
	/** {@code Google Gson} 的 <code>@Until</code> 注解常用的版本号常量 - {@code 1.1}。 */
	public static final double UNTIL_VERSION_11 = SINCE_VERSION_11;
	/** {@code Google Gson} 的 <code>@Until</code> 注解常用的版本号常量 - {@code 1.2}。 */
	public static final double UNTIL_VERSION_12 = SINCE_VERSION_12;

	/** 
	 * <p> 
	 * <code>JSONUtils</code> instances should NOT be constructed in standard programming. Instead, 
	 * the class should be used as <code>JSONUtils.fromJson("foo");</code>. 
	 * </p> 
	 * <p> 
	 * This constructor is public to permit tools that require a JavaBean instance to operate. 
	 * </p> 
	 */
	public JsonUtils() {
		super();
	}

	/** 
	 * 将给定的目标对象根据指定的条件参数转换成 {@code JSON} 格式的字符串。 
	 * <p /> 
	 * <strong>该方法转换发生错误时，不会抛出任何异常。若发生错误时，曾通对象返回 <code>"{}"</code>； 集合或数组对象返回 <code>"[]"</code> 
	 * </strong> 
	 *  
	 * @param target 目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @param isSerializeNulls 是否序列化 {@code null} 值字段。 
	 * @param version 字段的版本号注解。 
	 * @param datePattern 日期字段的格式化模式。 
	 * @param excludesFieldsWithoutExpose 是否排除未标注 {@literal @Expose} 注解的字段。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Type targetType,
			boolean isSerializeNulls, Double version, String datePattern,
			boolean excludesFieldsWithoutExpose) throws Exception{
		if (target == null)
			return EMPTY_JSON;
		GsonBuilder builder = new GsonBuilder();
		if (isSerializeNulls)
			builder.serializeNulls();
		if (version != null)
			builder.setVersion(version.doubleValue());
		if (StringUtils.isBlank(datePattern))
			datePattern = DEFAULT_DATE_PATTERN;
		builder.setDateFormat(datePattern);
		if (excludesFieldsWithoutExpose)
			builder.excludeFieldsWithoutExposeAnnotation();
		return toJson(target, targetType, builder);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法只用来转换普通的 {@code JavaBean} 对象。</strong> 
	 * <ul> 
	 * <li>该方法只会转换标有 {@literal @Expose} 注解的字段；</li> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法会转换所有未标注或已标注 {@literal @Since} 的字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target) throws Exception{
		return toJson(target, null, false, null, null, true);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法只用来转换普通的 {@code JavaBean} 对象。</strong> 
	 * <ul> 
	 * <li>该方法只会转换标有 {@literal @Expose} 注解的字段；</li> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法会转换所有未标注或已标注 {@literal @Since} 的字段；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param datePattern 日期字段的格式化模式。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, String datePattern) throws Exception{
		return toJson(target, null, false, null, datePattern, true);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法只用来转换普通的 {@code JavaBean} 对象。</strong> 
	 * <ul> 
	 * <li>该方法只会转换标有 {@literal @Expose} 注解的字段；</li> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param version 字段的版本号注解({@literal @Since})。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Double version) throws Exception{
		return toJson(target, null, false, version, null, true);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法只用来转换普通的 {@code JavaBean} 对象。</strong> 
	 * <ul> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法会转换所有未标注或已标注 {@literal @Since} 的字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param excludesFieldsWithoutExpose 是否排除未标注 {@literal @Expose} 注解的字段。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, boolean excludesFieldsWithoutExpose) throws Exception{
		return toJson(target, null, false, null, null,
				excludesFieldsWithoutExpose);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法只用来转换普通的 {@code JavaBean} 对象。</strong> 
	 * <ul> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param version 字段的版本号注解({@literal @Since})。 
	 * @param excludesFieldsWithoutExpose 是否排除未标注 {@literal @Expose} 注解的字段。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Double version, boolean excludesFieldsWithoutExpose) throws Exception{
		return toJson(target, null, false, version, null,
				excludesFieldsWithoutExpose);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法通常用来转换使用泛型的对象。</strong> 
	 * <ul> 
	 * <li>该方法只会转换标有 {@literal @Expose} 注解的字段；</li> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法会转换所有未标注或已标注 {@literal @Since} 的字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Type targetType) throws Exception{
		return toJson(target, targetType, false, null, null, true);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法通常用来转换使用泛型的对象。</strong> 
	 * <ul> 
	 * <li>该方法只会转换标有 {@literal @Expose} 注解的字段；</li> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @param version 字段的版本号注解({@literal @Since})。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Type targetType, Double version) throws Exception{
		return toJson(target, targetType, false, version, null, true);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法通常用来转换使用泛型的对象。</strong> 
	 * <ul> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法会转换所有未标注或已标注 {@literal @Since} 的字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @param excludesFieldsWithoutExpose 是否排除未标注 {@literal @Expose} 注解的字段。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Type targetType, boolean excludesFieldsWithoutExpose) throws Exception{
		return toJson(target, targetType, false, null, null,
				excludesFieldsWithoutExpose);
	}

	/** 
	 * 将给定的目标对象转换成 {@code JSON} 格式的字符串。<strong>此方法通常用来转换使用泛型的对象。</strong> 
	 * <ul> 
	 * <li>该方法不会转换 {@code null} 值字段；</li> 
	 * <li>该方法转换时使用默认的 日期/时间 格式化模式 - {@code yyyy-MM-dd HH:mm:ss SSS}；</li> 
	 * </ul> 
	 *  
	 * @param target 要转换成 {@code JSON} 的目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @param version 字段的版本号注解({@literal @Since})。 
	 * @param excludesFieldsWithoutExpose 是否排除未标注 {@literal @Expose} 注解的字段。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.0 
	 */
	public static String toJson(Object target, Type targetType, Double version, boolean excludesFieldsWithoutExpose) throws Exception{
		return toJson(target, targetType, false, version, null,
				excludesFieldsWithoutExpose);
	}

	/** 
	 * 将给定的 {@code JSON} 字符串转换成指定的类型对象。 
	 *  
	 * @param <T> 要转换的目标类型。 
	 * @param json 给定的 {@code JSON} 字符串。 
	 * @param token {@code com.google.gson.reflect.TypeToken} 的类型指示类对象。 
	 * @param datePattern 日期格式模式。 
	 * @return 给定的 {@code JSON} 字符串表示的指定的类型对象。 
	 * @since 1.0 
	 */
	public static <T> T fromJson(String json, TypeToken<T> token, String datePattern) throws Exception{
		if (StringUtils.isBlank(json)) {
			return null;
		}
		GsonBuilder builder = new GsonBuilder();
		if (StringUtils.isBlank(datePattern)) {
			datePattern = DEFAULT_DATE_PATTERN;
		}
		Gson gson = builder.create();
		return gson.fromJson(json, token.getType());
	}

	/** 
	 * 将给定的 {@code JSON} 字符串转换成指定的类型对象。 
	 *  
	 * @param <T> 要转换的目标类型。 
	 * @param json 给定的 {@code JSON} 字符串。 
	 * @param token {@code com.google.gson.reflect.TypeToken} 的类型指示类对象。 
	 * @return 给定的 {@code JSON} 字符串表示的指定的类型对象。 
	 * @since 1.0 
	 */
	public static <T> T fromJson(String json, TypeToken<T> token) throws Exception{
		return fromJson(json, token, null);
	}
	
	/**
	 * 将给定的 {@code JSON} 字符串转换成指定的类型对象。 
	 * 
	 * @param <T> 要转换的目标类型。 
	 * @param json 给定的 {@code JSON} 字符串。 
	 * @param type {@code java.lang.reflect.Type} 的类型指示类对象。 
	 * @return 给定的 {@code JSON} 字符串表示的指定的类型对象。
	 * @since 1.0 
	 */
	public static <T> T fromJson(String json, Type type) throws Exception{
		Gson gson = new Gson();
		return gson.fromJson(json, type);
	}

	/** 
	 * 将给定的 {@code JSON} 字符串转换成指定的类型对象。<strong>此方法通常用来转换普通的 {@code JavaBean} 对象。</strong> 
	 *  
	 * @param <T> 要转换的目标类型。 
	 * @param json 给定的 {@code JSON} 字符串。 
	 * @param clazz 要转换的目标类。 
	 * @param datePattern 日期格式模式。 
	 * @return 给定的 {@code JSON} 字符串表示的指定的类型对象。 
	 * @since 1.0 
	 */
	public static <T> T fromJson(String json, Class<T> clazz, String datePattern) throws Exception{
		if (StringUtils.isBlank(json)) {
			return null;
		}
		GsonBuilder builder = new GsonBuilder();
		if (StringUtils.isBlank(datePattern)) {
			datePattern = DEFAULT_DATE_PATTERN;
		}
		Gson gson = builder.create();
		return gson.fromJson(json, clazz);
	}

	/** 
	 * 将给定的 {@code JSON} 字符串转换成指定的类型对象。<strong>此方法通常用来转换普通的 {@code JavaBean} 对象。</strong> 
	 *  
	 * @param <T> 要转换的目标类型。 
	 * @param json 给定的 {@code JSON} 字符串。 
	 * @param clazz 要转换的目标类。 
	 * @return 给定的 {@code JSON} 字符串表示的指定的类型对象。 
	 * @since 1.0 
	 */
	public static <T> T fromJson(String json, Class<T> clazz) throws Exception{
		return fromJson(json, clazz, null);
	}
	
	/** 
	 * 将给定的目标对象根据{@code GsonBuilder} 所指定的条件参数转换成 {@code JSON} 格式的字符串。 
	 * <p /> 
	 * 该方法转换发生错误时，不会抛出任何异常。若发生错误时，{@code JavaBean} 对象返回 <code>"{}"</code>； 集合或数组对象返回 
	 * <code>"[]"</code>。 其本基本类型，返回相应的基本值。 
	 *  
	 * @param target 目标对象。 
	 * @param targetType 目标对象的类型。 
	 * @param builder 可定制的{@code Gson} 构建器。 
	 * @return 目标对象的 {@code JSON} 格式的字符串。 
	 * @since 1.1 
	 */
	public static String toJson(Object target, Type targetType,
			GsonBuilder builder) throws Exception{
		if (target == null)
			return EMPTY_JSON;
		Gson gson = null;
		if (builder == null) {
			gson = new Gson();
		} else {
			gson = builder.create();
		}
		String result = EMPTY_JSON;
		if (targetType == null) {
			result = gson.toJson(target);
		} else {
			result = gson.toJson(target, targetType);
		}
		return result;
	}
	
	public static String toJSON(Object target) throws Exception{
		String result = EMPTY_JSON;
		if (target == null)
			return EMPTY_JSON;
		Gson gson = new Gson();
		result = gson.toJson(target);
		return result;
	}
	
	public static List<Map<String, Object>> parseJSON2List(String jsonStr){
        JSONArray jsonArr = JSONArray.fromObject(jsonStr);
        List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
        Iterator<JSONObject> it = jsonArr.iterator();
        while(it.hasNext()){
            JSONObject json2 = it.next();
            list.add(parseJSON2Map(json2.toString()));
        }
        return list;
    }
    
   
    public static Map<String, Object> parseJSON2Map(String jsonStr){
        Map<String, Object> map = new HashMap<String, Object>();
        //最外层解析
        JSONObject json = JSONObject.fromObject(jsonStr);
        for(Object k : json.keySet()){
            Object v = json.get(k); 
            //如果内层还是数组的话，继续解析
            if(v instanceof JSONArray){
                List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
                Iterator<JSONObject> it = ((JSONArray)v).iterator();
                while(it.hasNext()){
                    JSONObject json2 = it.next();
                    list.add(parseJSON2Map(json2.toString()));
                }
                map.put(k.toString(), list);
            } else {
                map.put(k.toString(), v);
            }
        }
        return map;
    }
}